#!/usr/bin/env python
# -*- coding:utf8 -*-
# uncompyle6 version 2.15.1
# Python bytecode 2.7 (62211)
# Decompiled from: Python 2.7.10 (default, Jul  1 2017, 13:36:56) 
# [GCC 4.4.6 20110731 (Red Hat 4.4.6-4)]
# Embedded file name: ./esb/esb/utils/channel_tools.py
# Compiled at: 2017-11-16 15:44:28
"""
Tencent is pleased to support the open source community by making 蓝鲸智云(BlueKing) available.
Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved.
Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License.
You may obtain a copy of the License at http://opensource.org/licenses/MIT
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.

channel 辅助工具，辅助将 channel 数据入库，及生成SDK
"""
import re, os
from importlib import import_module
from django.conf import settings
from common.constants import API_TYPE_OP
from esb.component.base import get_components_manager
from components.esb_conf import BK_SYSTEMS, CUSTOM_APIS_REL_PATH
from esb.utils import fpath_to_module
from common.base_utils import smart_unicode
from . import config

def get_bk_systems():
    return BK_SYSTEMS


def get_custom_systems():
    custom_conf_module = get_custom_conf_module()
    if custom_conf_module:
        return getattr(custom_conf_module, 'SYSTEMS', [])
    return []


def get_bk_channels():
    """仅获取可显示的 channel
    :return
        {
            'CC': [
                {
                    'path': '',
                    'comp_codename': '',
                    'api_name': '',
                    'api_description': '',
                    'api_path': '',
                    'suggest_method': '',
                },
            ]
        }
    """
    channel_config = []
    channel_groups = config.ESB_CONFIG['config']['channel_groups']
    for channel_group_conf in channel_groups.values():
        channel_config.extend(channel_group_conf['preset_channels'])

    return get_channels_by_config(channel_config)


def get_custom_channels():
    """返回数据格式同 get_bk_channels """
    custom_conf_module = get_custom_conf_module()
    channels = getattr(custom_conf_module, 'CHANNELS', None)
    if not channels:
        return {}
    channel_config = []
    for channel in channels:
        channel_config.append((
         channel['path'], {'comp_codename': channel['comp_codename']}))

    return get_channels_by_config(channel_config)


def get_channels_by_config(channel_config):
    """
    :return: {
        "CC": [
            {
                "path": "",
                "comp_codename": "",
                "comp_conf_to_db": {},
                "system_name": "CC",
                "api_name": "xxx",
                "api_description": "xxx",
                "suggest_method": "GET",
                "api_path": "",
                "api_type": 1,
                "component_name": "",
            }
        ]
    }
    """
    system_channels = {}
    for path, value in channel_config:
        if value.get('is_hidden'):
            continue
        if path.startswith('/data/'):
            continue
        try:
            api_channel = get_api_data(value['comp_codename'])
        except Exception as ex:
            error_msg = u'[%s] get api data fail, ex: %s' % (value['comp_codename'], ex)
            print error_msg.encode('utf-8')
            continue

        api_channel.update({'path': path,
           'comp_conf_to_db': value.get('comp_conf_to_db'),
           'comp_codename': value['comp_codename']
           })
        system_channels.setdefault(api_channel['system_name'], [])
        system_channels[api_channel['system_name']].append(api_channel)

    return system_channels


def get_api_data_with_md(comp_codename):
    """从Markdown格式组件文档中抽取组件信息"""
    components_manager = get_components_manager()
    comp = components_manager.get_comp_by_name(comp_codename)
    if not comp:
        raise Exception("Can't find component class of %s" % comp_codename)
    comp_doc = comp.__doc__
    if isinstance(comp_doc, unicode):
        comp_doc = comp_doc if 1 else comp_doc.decode('utf-8')
        api_name = comp.get_component_name()
        api_path = ('/api/c/compapi/{system_name}/{api_name}/').format(system_name=comp.sys_name.lower(), api_name=api_name)
        api_label = re.search('apiLabel\s*(.+)', comp_doc)
        if api_label:
            api_label = api_label.group(1).strip()
        if not api_label:
            raise Exception("Can't find apiLabel in component document of %s" % comp_codename)
        api_method = re.search('apiMethod\s*(.+)', comp_doc)
        if api_method:
            api_method = api_method.group(1).strip()
        raise api_method or Exception("Can't find apiMethod in component document of %s" % comp_codename)
    return {'system_name': comp.sys_name,
       'api_name': api_name,
       'component_name': api_name,
       'api_description': api_label,
       'suggest_method': api_method.upper(),
       'api_path': api_path,
       'api_type': 1 if comp.api_type == API_TYPE_OP else 2,
       'comp_doc': comp_doc,
       'comp_codename': comp_codename
       }


def get_api_data(comp_codename):
    components_manager = get_components_manager()
    comp = components_manager.get_comp_by_name(comp_codename)
    if not comp:
        raise Exception(u'组件 %s 不存在' % comp_codename)
    comp_doc = get_comp_origin_doc(comp)
    comp_doc = smart_unicode(comp_doc)
    api_name = re.search('@apiName\s*(.+)', comp_doc)
    if api_name:
        api_name = api_name.group(1).strip()
    if not api_name:
        raise Exception(u'组件 %s @apiName 为空' % comp_codename)
    api_description = re.search('@apiDescription\s*(.+)', comp_doc)
    if api_description:
        api_description = api_description.group(1).strip()
    if not api_description:
        raise Exception(u'组件 %s @apiDescription 为空' % comp_codename)
    suggest_method = re.search('@api\s*\{(\w+)\}', comp_doc)
    if suggest_method:
        suggest_method = suggest_method.group(1).strip().upper()
    if not suggest_method:
        raise Exception(u'组件 %s @api 中方法为空' % comp_codename)
    if suggest_method not in ('GET', 'POST'):
        raise Exception(u'组件 %s @api 中方法不是 GET/POST，请检查确认' % comp_codename)
    api_path = re.search('@api\s*\{\w+\}\s*([\w/]+)', comp_doc)
    if api_path:
        api_path = api_path.group(1).strip()
    if not api_path:
        raise Exception(u'组件 %s @api 中组件路径为空' % comp_codename)
    return {'system_name': comp.sys_name,
       'api_name': api_name,
       'api_description': api_description,
       'suggest_method': suggest_method,
       'api_path': api_path,
       'api_type': 1 if comp.api_type == API_TYPE_OP else 2,
       'component_name': comp.get_component_name()
       }


def get_custom_conf_module():
    conf_path = os.path.join(CUSTOM_APIS_REL_PATH, 'conf.py')
    try:
        return import_module(fpath_to_module(conf_path))
    except:
        return

    return


def get_comp_origin_doc(comp):
    comp_doc = comp.__doc__.strip()
    if re.search('@api\b', comp_doc):
        return comp_doc
    comp_module_name = comp.__module__
    sys_module_name, comp_py_name = comp_module_name.rsplit('.', 1)
    doc_path = os.path.join(settings.BASE_DIR, sys_module_name.replace('.', os.sep), 'apidoc/%s.js' % comp_py_name)
    if not os.path.exists(doc_path):
        raise Exception(u'component __doc__ is empty and js doc(%s) is not exists' % doc_path)
    with open(doc_path, 'r') as (fp):
        comp_doc = fp.read()
    return comp_doc
